export const componentJson = {
  tag: 'el-card',
  props: [{ prop: 'header', type: 'String', value: 'header' }],
  children: [
    {
      tag: 'r-form',
      ref: 'form',
      style: 'text-align: left; width: 40%; margin-left: 30%',
      props: [
        {
          prop: 'columns',
          type: 'Array',
          name: 'formColumns'
        },
        { prop: 'submit', type: 'Object', name: 'formSubmit' }
      ],
      events: [{ event: 'change', func: 'onChange' }]
    },
    {
      tag: 'r-form',
      ref: 'form2',
      style: 'text-align: left; width: 40%; margin-left: 30%',
      props: [],
      events: [{ event: 'submit', func: 'onSubmit' }]
    }
  ]
}

export function genComponentJson(componentJson, ref, json) {
  if (!componentJson || !ref) {
    return json
  }
  // find refJson
  // add children
  let parent = findParentJson(componentJson, ref)
  parent.children = [...parent.children, json]
  return componentJson
}

function findParentJson(json, ref) {
  if (json.ref == ref) {
    return json
  }
  if (!!json.children) {
    for (let child of json.children) {
      let temp = findParentJson(child, ref)
      if (!!temp) {
        return temp
      }
    }
    // return json.children.find((j) => findParentJson(j, ref))
  }
  return null
}

export function newComponentJson(json, tag) {
  const { props, events } = findPropsAndEvents(json)
  return {
    tag: tag,
    ref: '',
    style: '',
    class: '',
    props: props
      .filter((p) => !p.source && !!p.name)
      .map((p) => {
        return { prop: p.name, type: p.type }
      }),
    events: events
      .filter((e) => !e.source && !!e.func)
      .map((e) => {
        return { event: e.event, args: e.args }
      })
  }
}

import { parseComponent } from 'vue-template-compiler'
// const compiler = require('vue-template-compiler')

import { js_beautify, css_beautify, html_beautify } from 'js-beautify'

import { addStylesClient } from './style-loader/addStylesClient'
import { genStyleInjectionCode } from './style-loader/styleInjection'

const stylesUpdateHandler = addStylesClient('dynamic-style', {})

export function parseComponentByStr(sourceCode) {
  const { template, script, styles, customBlocks, errors } = parseComponent(sourceCode)
  // console.log(this.sfcDescriptor);

  const templateCode = template ? template.content.trim() : ``
  const scriptCode = script ? script.content.trim() : ``

  const componentScript = {}
  const evalScriptCode = scriptCode.replace(/export\s+default/, 'componentScript =')
  eval(evalScriptCode)

  // 构建组件
  const component = {}
  component.template = templateCode
  // component.script = componentScript
  extend(component, componentScript)

  const { styleCode, styleArray } = genStyleInjectionCode(styles)
  stylesUpdateHandler(styleArray)

  return { component, sourceCode }
}

export function parseComponentByJson(json) {
  let { templateCode, scriptCode, styleCode } = parseComponentJson(json)

  const componentScript = {}
  const evalScriptCode = scriptCode.replace(/export\s+default/, 'componentScript =')
  eval(evalScriptCode)

  const component = {}
  component.template = templateCode
  // component.script = componentScript
  extend(component, componentScript)

  let sourceCode = `
<template>
  ${html_beautify(templateCode)}
</template>
<script>
  ${js_beautify(scriptCode)}
</script>
<style scoped>
  ${css_beautify(styleCode)}
</style>
  `
  return { component, sourceCode, json }
}

function parseComponentJson(json) {
  return { templateCode: genTemplate(json), scriptCode: genScript(json), styleCode: genStyle(json) }
}

//-----------------------------------------
function genTemplate(json) {
  return `
    <${json.tag}${genAttr(['ref', 'style', 'class'], json)}${genPropsAttr(json)}${genEventsAttr(json)}>
    ${!!json.children ? json.children.map((c) => genTemplate(c)).join('') : ''}
    </${json.tag}>
`
}

// const genTab = (level) => {
//   let step = ''
//   for (let i = 0; i < level; i++) {
//     step += '  '
//   }
//   return step
// }

const genAttr = (keys, json) => {
  return keys.map((k) => (!!json[k] ? ` ${k}="${json[k]}"` : '')).join('')
}

const genPropsAttr = (json) => {
  if (!json.props) {
    return ''
  }
  return json.props
    .filter((p) => !!p.value || !!p.name)
    .map((p) => {
      if (!!p.value && !p.name) {
        if (p?.type === 'String') {
          return ` ${p.prop}="${p.value}"`
        } else if (p?.type === 'Boolean') {
          return ` :${p.prop}="${p.value}"`
        }
        p.name = json.ref.replace(/-/g, '_') + p.prop
        // return ` :${p.prop}="${p.value}"`
        // return ``
      }
      return ` :${p.prop}="${p.name}"`
    })
    .join('')
}

const genEventsAttr = (json) => {
  if (!json.events) {
    return ''
  }
  return json.events.map((e) => (!!e.func ? ` @${e.event}="${e.func}"` : '')).join('')
}

//------------------------------------------------------

function genScript(json) {
  console.log(json)
  let { props, events } = findPropsAndEvents(json)
  return `
export default {
  data() {
    return {
      ${genData(props)}
    }
  },
  props:{
    ${genProps(props)}
  },
  methods: {
    ${genMethods(events)}
  }
}
`
}

const findPropsAndEvents = (json) => {
  let propsAndEvents = { props: [], events: [] }
  if (!!json.children) {
    for (let child of json.children) {
      let dam = findPropsAndEvents(child)
      propsAndEvents = { props: [...propsAndEvents.props, ...dam.props], events: [...propsAndEvents.events, ...dam.events] }
    }
  }
  if (!!json.props) {
    propsAndEvents.props = [...propsAndEvents.props, ...json.props]
  }
  if (!!json.events) {
    propsAndEvents.events = [...propsAndEvents.events, ...json.events]
  }
  return propsAndEvents
}

const genProps = (props) => {
  return props
    .filter((p) => !p.source && !!p.name)
    .map((p) => {
      return `'${p.name}' : {type: ${p.type}},`
    })
    .join('')
}

const genData = (props) => {
  return props
    .filter((p) => !!p.source && !!p.name)
    .map((p) => {
      return `'${p.name}' : ${genDefaultValue(p)},`
    })
    .join('')
}
const genDefaultValue = (p) => {
  if (Object.prototype.hasOwnProperty.call(p, 'value')) {
    return p['value']
  }

  if (p.type === 'String') {
    return "''"
  } else if (p.type === 'Boolean') {
    return 'false'
  } else if (p.type === 'Array') {
    return '[]'
  } else if (p.type === 'Object') {
    return '{}'
  }
}

const genMethods = (events) => {
  return events
    .filter((e) => !!e.func)
    .map((e) => {
      if (!e.source) {
        return `${e.func} (${e.args || ''}){ this.$emit('${e.event}' ${e.args ? ',' + e.args : ''})},`
      }
      return `${e.func} (${e.args || ''}){${e.content || ''}},`
    })
    .join('')
}

//------------------------------------
function genStyle(json) {
  return ``
}

const isString = (val) => typeof val === 'string'
const isObject = (val) => val !== null && typeof val === 'object'
const isArray = Array.isArray

function extend(to, _from) {
  for (let key in _from) {
    to[key] = _from[key]
  }
  return to
}

// <template>

// <el-card header="header">
//     <r-form ref="form" style="text-align: left; width: 40%; margin-left: 30%"
//     :columns="[]" :submit="{}" @change= "onChange"></r-form>
//     <r-form ref="form2" style="text-align: left; width: 40%; margin-left: 30%"
//     :columns="[]" :submit="{}" @submit= "onSubmit"></r-form>
// </el-card>

// </template>
// <script>
// export default {
//   data() {
//     return {
//         //todo
//     }
//   },
//   methods: {
//     onSubmit(formData) {
//       //todo
//     },
//     onChange(formData) {
//       //todo
//     }
//   }

// }
// </script>
// <style>

// </style>

// export function parserComponentJson(json) {
//   let prefix = '',
//     suffix = ''
//   prefix = `<${json.tag} ref="${json.ref}"  style="${json.style}">`
//   if (!!json.children) {
//     suffix = `</${json.tag}>`
//     for (let child of json.children) {
//       prefix += parserComponentJson(child)
//     }
//   } else {
//     prefix = prefix + `</${json.tag}>`
//   }

//   return prefix + suffix
// }
